package org.idol.generator.codegen.service;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.codegen.AbstractJavaGenerator;

import java.util.*;

import static org.mybatis.generator.internal.util.messages.Messages.getString;
import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;

/**
 * @author coco
 * @date 2020-06-22 12:51
 **/
public class ServiceImplGenerator extends AbstractJavaGenerator {

    public ServiceImplGenerator(String project) {
        super(project);
    }

    @Override
    public List<CompilationUnit> getCompilationUnits() {
        FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();
        progressCallback.startTask(getString(
                "Progress.20", table.toString())); //$NON-NLS-1$
        CommentGenerator commentGenerator = context.getCommentGenerator();
        FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                introspectedTable.getServiceJavaImplType());

        Plugin plugins = context.getPlugins();

        TopLevelClass topLevelClass = new TopLevelClass(type);
        topLevelClass.setVisibility(JavaVisibility.PUBLIC);
        topLevelClass.addAnnotation("@Service");
        topLevelClass.addImportedType("org.springframework.stereotype.Service");
        commentGenerator.addJavaFileComment(topLevelClass);

        FullyQualifiedJavaType superClass = new FullyQualifiedJavaType(
                introspectedTable.getServiceJavaInterfaceType());
        topLevelClass.addSuperInterface(superClass);
        topLevelClass.addImportedType(superClass);
        String rootServiceImpl = context.getProperty("rootServiceImpl");
        String rootBlobsServiceImpl = context.getProperty("rootBlobsServiceImpl");
        if (stringHasValue(rootServiceImpl)) {
            boolean b = introspectedTable.hasBLOBColumns();
            FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(
                    rootServiceImpl);
            if (b) {
                fqjt = new FullyQualifiedJavaType(
                        rootBlobsServiceImpl);
            }
            FullyQualifiedJavaType parameterType = introspectedTable.getRules()
                    .calculateAllFieldsClass();
            fqjt.addTypeArgument(parameterType);
            FullyQualifiedJavaType exampleType = new FullyQualifiedJavaType(
                    introspectedTable.getExampleType());
            fqjt.addTypeArgument(exampleType);
            FullyQualifiedJavaType javaMapper = new FullyQualifiedJavaType(
                    introspectedTable.getMyBatis3JavaMapperType());
            fqjt.addTypeArgument(javaMapper);
            topLevelClass.addImportedType(javaMapper);
            topLevelClass.addImportedType(exampleType);
            topLevelClass.addImportedType(parameterType);
            topLevelClass.addImportedType(fqjt);
            topLevelClass.setSuperClass(fqjt);
        }

        commentGenerator.addServiceClassComment(topLevelClass, introspectedTable);


/*
        topLevelClass.addImportedType("javax.annotation.Resource");


        Field field = new Field(firstLowCase(javaMapper.getShortName()), javaMapper);
        field.addAnnotation("@Resource");
        field.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(field);


        addServiceMethod(topLevelClass,javaMapper.getShortName());*/


        List<CompilationUnit> answer = new ArrayList<>();

        if (context.getPlugins().clientServiceImplGenerated(topLevelClass, introspectedTable)) {
            answer.add(topLevelClass);
        }

        List<CompilationUnit> extraCompilationUnits = getExtraCompilationUnits();
        if (extraCompilationUnits != null) {
            answer.addAll(extraCompilationUnits);
        }
        return answer;
    }

    protected void addServiceMethod(TopLevelClass topLevelClass,String mapperName) {
        createQueryByIdImpl(topLevelClass,mapperName);
    }

    /**
     *  queryById
     * @param topLevelClass
     * @param mapperName
     */
    private void createQueryByIdImpl(TopLevelClass topLevelClass,String mapperName) {
        Set<FullyQualifiedJavaType> importedTypes = new TreeSet<>();


        Method method = new Method(introspectedTable.getQueryByIdType());
        FullyQualifiedJavaType returnType = FullyQualifiedJavaType.getOptionalInstance();
        FullyQualifiedJavaType typeArgument = introspectedTable.getRules()
                .calculateAllFieldsClass();
        returnType.addTypeArgument(typeArgument);

        importedTypes.add(returnType);
        importedTypes.add(typeArgument);

        method.setReturnType(returnType);
        method.addAnnotation("@Override");

        method.setVisibility(JavaVisibility.PUBLIC);
        List<String> lines = new ArrayList<>();
        StringBuffer sb = new StringBuffer();
        String key = "";
        sb.append("if (");
        if (introspectedTable.getRules().generatePrimaryKeyClass()) {
            FullyQualifiedJavaType keyType = new FullyQualifiedJavaType(
                    introspectedTable.getPrimaryKeyType());
            importedTypes.add(keyType);
            method.addParameter(new Parameter(keyType, "key")); //$NON-NLS-1$
            sb.append("Objects.nonNull(key)");
            key = "key";
        } else {
            // no primary key class - fields are in the base class
            // if more than one PK field, then we need to annotate the
            // parameters
            // for MyBatis3
            List<IntrospectedColumn> introspectedColumns = introspectedTable
                    .getPrimaryKeyColumns();
            for (IntrospectedColumn introspectedColumn : introspectedColumns) {
                FullyQualifiedJavaType keyType = introspectedColumn
                        .getFullyQualifiedJavaType();
                importedTypes.add(keyType);
                Parameter parameter = new Parameter(keyType, introspectedColumn
                        .getJavaProperty());
                method.addParameter(parameter);
                if (introspectedColumns.indexOf(introspectedColumn)+1 == introspectedColumns.size()) {
                    sb.append("Objects.nonNull("+introspectedColumn.getJavaProperty()+")");
                    key += introspectedColumn.getJavaProperty();
                } else {
                    sb.append("Objects.nonNull("+introspectedColumn.getJavaProperty()+") && ");
                    key += introspectedColumn.getJavaProperty()+",";
                }

            }
        }
        importedTypes.add(FullyQualifiedJavaType.getObjectsInstance());
        //commentGenerator.addGeneralMethodComment(method, introspectedTable);
        sb.append(") {");
        lines.add(sb.toString());
        sb.setLength(0);
        sb.append("return Optional.empty();");
        lines.add(sb.toString());
        sb.setLength(0);
        sb.append("}");
        lines.add(sb.toString());
        sb.setLength(0);
        sb.append("return Optional.ofNullable("+firstLowCase(mapperName)+"."+introspectedTable.getSelectByPrimaryKeyStatementId()+"("+key+"));");
        lines.add(sb.toString());

        method.addBodyLines(lines);
        topLevelClass.addImportedTypes(importedTypes);
        topLevelClass.addMethod(method);
    }

    private String firstLowCase(String name ) {
        if (name != null && name.length()>0) {
            return name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toLowerCase());
        } else {
            return name;
        }
    }

    public List<CompilationUnit> getExtraCompilationUnits() {
        return Collections.emptyList();
    }
}
